From e1de1c738b02c3bbfb3c23849ba5c4a85f8a474a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 31 Jul 2014 12:20:05 -0700 Subject: [PATCH] Optimize freshness of git repos This commit cuts down on the number of invocations of `git` to make the "happy path" of an up-to-date git repo much smoother. The precise information is also applied from the lockfile to speed things up. --- src/cargo/sources/git/mod.rs | 2 +- src/cargo/sources/git/source.rs | 17 ++++++---- src/cargo/sources/git/utils.rs | 58 +++++++++++++++++++++------------ 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/cargo/sources/git/mod.rs b/src/cargo/sources/git/mod.rs index f9ec6d668..8b1ba4977 100644 --- a/src/cargo/sources/git/mod.rs +++ b/src/cargo/sources/git/mod.rs @@ -1,4 +1,4 @@ -pub use self::utils::{GitRemote,GitDatabase,GitCheckout}; +pub use self::utils::{GitRemote, GitDatabase, GitCheckout, GitRevision}; pub use self::source::{GitSource, canonicalize_url}; mod utils; mod source; diff --git a/src/cargo/sources/git/source.rs b/src/cargo/sources/git/source.rs index 61759e65e..925b9ae24 100644 --- a/src/cargo/sources/git/source.rs +++ b/src/cargo/sources/git/source.rs @@ -155,9 +155,9 @@ impl<'a, 'b> Registry for GitSource<'a, 'b> { impl<'a, 'b> Source for GitSource<'a, 'b> { fn update(&mut self) -> CargoResult<()> { - let should_update = self.config.update_remotes() || { - !self.remote.has_ref(&self.db_path, self.reference.as_slice()).is_ok() - }; + let actual_rev = self.remote.rev_for(&self.db_path, + self.reference.as_slice()); + let should_update = self.config.update_remotes() || actual_rev.is_err(); let repo = if should_update { try!(self.config.shell().status("Updating", @@ -168,11 +168,14 @@ impl<'a, 'b> Source for GitSource<'a, 'b> { } else { self.remote.db_at(&self.db_path) }; + let actual_rev = match actual_rev { + Ok(rev) => rev, + Err(..) => try!(repo.rev_for(self.reference.as_slice())), + }; - let checkout = try!(repo.copy_to(self.reference.as_slice(), - &self.checkout_path)); + try!(repo.copy_to(actual_rev.clone(), &self.checkout_path)); - let source_id = self.source_id.with_precise(checkout.get_rev().to_string()); + let source_id = self.source_id.with_precise(actual_rev.to_string()); let path_source = PathSource::new(&self.checkout_path, &source_id); self.path_source = Some(path_source); @@ -191,7 +194,7 @@ impl<'a, 'b> Source for GitSource<'a, 'b> { fn fingerprint(&self, _pkg: &Package) -> CargoResult { let db = self.remote.db_at(&self.db_path); - db.rev_for(self.reference.as_slice()) + db.rev_for(self.reference.as_slice()).map(|r| r.to_string()) } } diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs index 3a3a0a583..4caab7880 100644 --- a/src/cargo/sources/git/utils.rs +++ b/src/cargo/sources/git/utils.rs @@ -13,6 +13,9 @@ pub enum GitReference { Other(String) } +#[deriving(PartialEq,Clone,Encodable)] +pub struct GitRevision(String); + impl GitReference { pub fn for_str(string: S) -> GitReference { if string.as_slice() == "master" { @@ -38,6 +41,18 @@ impl Show for GitReference { } } +impl Str for GitRevision { + fn as_slice(&self) -> &str { + let GitRevision(ref me) = *self; + me.as_slice() + } +} + +impl Show for GitRevision { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + self.as_slice().fmt(f) + } +} macro_rules! git( ($config:expr, $($arg:expr),+) => ( @@ -104,15 +119,13 @@ impl> Encodable for GitDatabase { pub struct GitCheckout { database: GitDatabase, location: Path, - reference: GitReference, - revision: String, + revision: GitRevision, } #[deriving(Encodable)] pub struct EncodableGitCheckout { database: GitDatabase, location: String, - reference: String, revision: String, } @@ -121,7 +134,6 @@ impl> Encodable for GitCheckout { EncodableGitCheckout { database: self.database.clone(), location: self.location.display().to_string(), - reference: self.reference.to_string(), revision: self.revision.to_string() }.encode(s) } @@ -138,9 +150,9 @@ impl GitRemote { &self.location } - pub fn has_ref(&self, path: &Path, reference: S) -> CargoResult<()> { - git_output!(*path, "rev-parse", reference.as_slice()); - Ok(()) + pub fn rev_for(&self, path: &Path, reference: S) + -> CargoResult { + Ok(GitRevision(git_output!(*path, "rev-parse", reference.as_slice()))) } pub fn checkout(&self, into: &Path) -> CargoResult { @@ -177,34 +189,38 @@ impl GitDatabase { &self.path } - pub fn copy_to(&self, reference: S, - dest: &Path) -> CargoResult { + pub fn copy_to(&self, rev: GitRevision, dest: &Path) + -> CargoResult { let checkout = try!(GitCheckout::clone_into(dest, self.clone(), - GitReference::for_str(reference.as_slice()))); + rev.clone())); - if self.remote.has_ref(dest, reference.as_slice()).is_err() { - try!(checkout.fetch()); + match self.remote.rev_for(dest, "HEAD") { + Ok(ref head) if rev == *head => return Ok(checkout), + _ => try!(checkout.fetch()), } - try!(checkout.reset(reference.as_slice())); + + try!(checkout.reset()); try!(checkout.update_submodules()); Ok(checkout) } - pub fn rev_for(&self, reference: S) -> CargoResult { - Ok(git_output!(self.path, "rev-parse", reference.as_slice())) + pub fn rev_for(&self, reference: S) -> CargoResult { + self.remote.rev_for(&self.path, reference) } + pub fn has_ref(&self, reference: S) -> CargoResult<()> { + git_output!(self.path, "rev-parse", "--verify", reference.as_slice()); + Ok(()) + } } impl GitCheckout { fn clone_into(into: &Path, database: GitDatabase, - reference: GitReference) -> CargoResult { - let revision = try!(database.rev_for(reference.as_slice())); + revision: GitRevision) -> CargoResult { let checkout = GitCheckout { location: into.clone(), database: database, - reference: reference, revision: revision, }; @@ -241,6 +257,7 @@ impl GitCheckout { git!(dirname, "clone", "--no-checkout", "--quiet", self.get_source(), &self.location); + try!(self.reset()); Ok(()) } @@ -270,8 +287,9 @@ impl GitCheckout { Ok(()) } - fn reset(&self, revision: &str) -> CargoResult<()> { - Ok(git!(self.location, "reset", "-q", "--hard", revision)) + fn reset(&self) -> CargoResult<()> { + Ok(git!(self.location, "reset", "-q", "--hard", + self.revision.as_slice())) } fn update_submodules(&self) -> CargoResult<()> { -- 2.30.2